2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 //==============================================================================
28 This file contains all the mess that creates an NPAPI interface, and connects
29 that interface to your BrowserPluginComponent object.
32 //==============================================================================
33 #if defined (__APPLE__) && ! JUCE_NPAPI_WRAPPED_IN_MM
34 #error "On the Mac, you can't compile this .cpp file directly - use juce_NPAPI_GlueCode.mm instead"
39 //==============================================================================
45 #include "npapi/npupp.h"
47 // Cunning trick used to add functions to export list and avoid messing about with .def files.
48 // (can't add a declspec because the functions have already been pre-declared in the npapi headers).
49 #define EXPORTED_FUNCTION comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
51 //==============================================================================
52 #elif defined (__APPLE__)
55 #include <WebKit/npapi.h>
56 #include <WebKit/npfunctions.h>
57 #include <WebKit/npruntime.h>
59 //==============================================================================
64 #include "npruntime.h"
68 //==============================================================================
69 #include "juce_IncludeBrowserPluginInfo.h"
70 #include "../../../juce_amalgamated.h"
71 #include "juce_BrowserPluginComponent.h"
73 #if JUCE_MAC && JUCE_DEBUG && 0
75 static void log (const String
& s
)
77 std::ofstream
file ("/Users/jules/Desktop/log.txt", std::ios::out
| std::ios::app
);
78 file
<< s
<< std::endl
;
84 //==============================================================================
86 static const String
nsStringToJuce (NSString
* s
) { return String::fromUTF8 ([s UTF8String
]); }
87 static NSString
* juceStringToNS (const String
& s
) { return [NSString stringWithUTF8String
: s
.toUTF8()]; }
92 NPError
NP_Initialize (NPNetscapeFuncs
*);
93 NPError
NP_GetEntryPoints (NPPluginFuncs
*);
94 NPError
NP_Shutdown();
98 #ifndef NP_CLASS_STRUCT_VERSION_ENUM // fill in some symbols that are missing from the OSX 10.4 SDK
99 #define NPNVpluginDrawingModel 1000
100 #define NPDrawingModelCoreGraphics 1
102 typedef struct NP_CGContext
104 CGContextRef context
;
111 //==============================================================================
112 static NPNetscapeFuncs browser
;
113 String browserVersionDesc
;
115 //==============================================================================
116 NPError
NP_GetValue (void* future
, NPPVariable variable
, void* value
)
118 return NPP_GetValue ((NPP_t
*) future
, variable
, value
);
121 #if JUCE_WINDOWS || JUCE_MAC
122 NPError OSCALL
NP_GetEntryPoints (NPPluginFuncs
* funcs
)
125 #pragma EXPORTED_FUNCTION
128 log ("NP_GetEntryPoints");
129 if (funcs
== 0 || (funcs
->size
> 0 && funcs
->size
< sizeof (NPPluginFuncs
)))
130 return NPERR_INVALID_FUNCTABLE_ERROR
;
132 funcs
->size
= sizeof (NPPluginFuncs
);
133 funcs
->version
= (NP_VERSION_MAJOR
<< 8) | NP_VERSION_MINOR
;
134 funcs
->newp
= NPP_New
;
135 funcs
->destroy
= NPP_Destroy
;
136 funcs
->setwindow
= NPP_SetWindow
;
137 funcs
->newstream
= NPP_NewStream
;
138 funcs
->destroystream
= NPP_DestroyStream
;
139 funcs
->asfile
= NPP_StreamAsFile
;
140 funcs
->writeready
= NPP_WriteReady
;
142 funcs
->write
= (NPP_WriteProcPtr
) NPP_Write
;
144 funcs
->write
= NPP_Write
;
146 funcs
->print
= NPP_Print
;
147 funcs
->event
= NPP_HandleEvent
;
148 funcs
->urlnotify
= NPP_URLNotify
;
149 funcs
->getvalue
= NPP_GetValue
;
150 funcs
->setvalue
= NPP_SetValue
;
151 funcs
->javaClass
= nullptr;
153 return NPERR_NO_ERROR
;
157 NPError OSCALL
NP_Initialize (NPNetscapeFuncs
* funcs
159 , NPPluginFuncs
* pluginFuncs
164 #pragma EXPORTED_FUNCTION
167 log ("NP_Initialize");
169 return NPERR_INVALID_FUNCTABLE_ERROR
;
171 if (((funcs
->version
>> 8) & 0xff) > NP_VERSION_MAJOR
)
172 return NPERR_INCOMPATIBLE_VERSION_ERROR
;
174 zerostruct (browser
);
175 memcpy (&browser
, funcs
, jmin ((size_t) funcs
->size
, sizeof (browser
)));
178 pluginFuncs
->version
= (NP_VERSION_MAJOR
<< 8) + NP_VERSION_MINOR
;
179 pluginFuncs
->size
= sizeof (NPPluginFuncs
);
180 pluginFuncs
->newp
= NewNPP_NewProc (NPP_New
);
181 pluginFuncs
->destroy
= NewNPP_DestroyProc (NPP_Destroy
);
182 pluginFuncs
->setwindow
= NewNPP_SetWindowProc (NPP_SetWindow
);
183 pluginFuncs
->newstream
= NewNPP_NewStreamProc (NPP_NewStream
);
184 pluginFuncs
->destroystream
= NewNPP_DestroyStreamProc (NPP_DestroyStream
);
185 pluginFuncs
->asfile
= NewNPP_StreamAsFileProc (NPP_StreamAsFile
);
186 pluginFuncs
->writeready
= NewNPP_WriteReadyProc (NPP_WriteReady
);
187 pluginFuncs
->write
= NewNPP_WriteProc (NPP_Write
);
188 pluginFuncs
->print
= NewNPP_PrintProc (NPP_Print
);
189 pluginFuncs
->urlnotify
= NewNPP_URLNotifyProc (NPP_URLNotify
);
190 pluginFuncs
->event
= 0;
191 pluginFuncs
->getvalue
= NewNPP_GetValueProc (NPP_GetValue
);
193 pluginFuncs
->javaClass
= NPP_GetJavaClass();
197 return NPERR_NO_ERROR
;
200 NPError OSCALL
NP_Shutdown()
203 #pragma EXPORTED_FUNCTION
207 return NPERR_NO_ERROR
;
210 char* NP_GetMIMEDescription()
212 log ("NP_GetMIMEDescription");
213 static String mimeDesc
;
215 mimeDesc
= String (T(JuceBrowserPlugin_MimeType
))
216 + ":" + String (T(JuceBrowserPlugin_FileSuffix
))
217 + ":" + String (T(JuceBrowserPlugin_Name
));
219 return (char*) (const char*) mimeDesc
.toUTF8();
222 //==============================================================================
224 NPError NPN_GetURLNotify (NPP instance, const char *url, const char *target, void* notifyData)
226 return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
227 ? browser.geturlnotify (instance, url, target, notifyData);
228 : NPERR_INCOMPATIBLE_VERSION_ERROR;
231 NPError NPN_PostURLNotify (NPP instance, const char* url, const char* window, uint32 len, const char* buf, NPBool file, void* notifyData)
233 return (browser.version & 0xFF) >= NPVERS_HAS_NOTIFICATION
234 ? browser.posturlnotify (instance, url, window, len, buf, file, notifyData)
235 : NPERR_INCOMPATIBLE_VERSION_ERROR;
238 NPError NPN_NewStream (NPP instance, NPMIMEType type, const char* target, NPStream** stream)
240 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
241 ? browser.newstream (instance, type, target, stream)
242 : NPERR_INCOMPATIBLE_VERSION_ERROR;
245 int32 NPN_Write (NPP instance, NPStream *stream, int32 len, void *buffer)
247 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
248 ? browser.write (instance, stream, len, buffer)
252 NPError NPN_DestroyStream (NPP instance, NPStream* stream, NPError reason)
254 return (browser.version & 0xFF) >= NPVERS_HAS_STREAMOUTPUT
255 ? browser.destroystream (instance, stream, reason)
256 : NPERR_INCOMPATIBLE_VERSION_ERROR;
260 //==============================================================================
261 class BrowserPluginHolderComponent
: public Component
264 //==============================================================================
265 BrowserPluginHolderComponent (NPP npp_
)
268 log ("BrowserPluginHolderComponent created");
273 currentParentView
= 0;
277 setWantsKeyboardFocus (false);
279 addAndMakeVisible (child
= createBrowserPlugin());
280 jassert (child
!= nullptr); // You have to create one of these!
283 ~BrowserPluginHolderComponent()
285 log ("BrowserPluginHolderComponent deleted");
290 //==============================================================================
291 void paint (Graphics
& g
)
293 if (child
== nullptr || ! child
->isOpaque())
294 g
.fillAll (Colours::white
);
299 if (child
!= nullptr)
300 child
->setBounds (getLocalBounds());
303 const var
getObject()
305 return child
->getJavascriptObject();
308 //==============================================================================
310 ScopedPointer
<BrowserPluginComponent
> child
;
314 //==============================================================================
319 void resizeToParentWindow (const int requestedWidth
= 0, const int requestedHeight
= 0)
321 if (IsWindow (parentHWND
))
324 GetWindowRect (parentHWND
, &r
);
326 int w
= r
.right
- r
.left
;
327 int h
= r
.bottom
- r
.top
;
329 if (w
== 0 || h
== 0)
331 w
= requestedWidth
; // On Safari, the HWND can have a zero-size, so we might need to
332 h
= requestedHeight
; // force it to the size that the NPAPI call asked for..
333 MoveWindow (parentHWND
, r
.left
, r
.top
, w
, h
, TRUE
);
336 setBounds (0, 0, w
, h
);
340 static LRESULT CALLBACK
interceptingWinProc (HWND hWnd
, UINT msg
, WPARAM wParam
, LPARAM lParam
)
347 HDC hdc
= BeginPaint (hWnd
, &ps
);
348 EndPaint (hWnd
, &ps
);
355 case WM_WINDOWPOSCHANGING
:
356 case WM_WINDOWPOSCHANGED
:
357 //if ((((WINDOWPOS*) lParam)->flags & SWP_NOSIZE) == 0)
359 BrowserPluginHolderComponent
* const comp
= (BrowserPluginHolderComponent
*) GetWindowLongPtr (hWnd
, GWLP_USERDATA
);
360 comp
->resizeToParentWindow();
368 return DefWindowProc (hWnd
, msg
, wParam
, lParam
);
372 void setWindow (NPWindow
* window
)
374 HWND newHWND
= (window
!= nullptr ? ((HWND
) window
->window
) : 0);
376 if (parentHWND
!= newHWND
)
381 if (IsWindow (parentHWND
))
383 SubclassWindow (parentHWND
, oldWinProc
); // restore the old winproc..
387 parentHWND
= newHWND
;
391 addToDesktop (0, parentHWND
);
394 oldWinProc
= SubclassWindow (parentHWND
, (WNDPROC
) interceptingWinProc
);
396 jassert (GetWindowLongPtr (parentHWND
, GWLP_USERDATA
) == 0);
397 SetWindowLongPtr (parentHWND
, GWLP_USERDATA
, (LONG_PTR
) this);
399 resizeToParentWindow (window
->width
, window
->height
);
404 //==============================================================================
406 NSView
* currentParentView
;
408 NSView
* findViewAt (NSView
* parent
, float x
, float y
) const
410 NSRect frame
= [parent frame
];
411 NSRect bounds
= [parent bounds
];
415 Rectangle
<int> rr (frame
.origin
.x
, frame
.origin
.y
, frame
.size
.width
, frame
.size
.height
);
416 Rectangle
<int> rr2 (bounds
.origin
.x
, bounds
.origin
.y
, bounds
.size
.width
, bounds
.size
.height
);
417 //log (String ((int) x) + ", " + String ((int) y) + " - " + nsStringToJuce([parent description]) + " " + rr.toString() + " " + rr2.toString());
419 if (x
>= 0 && x
< frame
.size
.width
&& y
>= 0 && y
< frame
.size
.height
)
421 x
+= bounds
.origin
.x
; // adjust for scrolling panels
422 y
+= bounds
.origin
.y
;
424 for (int i
= [[parent subviews
] count
]; --i
>= 0;)
426 NSView
* v
= (NSView
*) [[parent subviews
] objectAtIndex
: i
];
428 if (v
!= (NSView
*) getWindowHandle() && ! [v isHidden
])
430 NSView
* found
= findViewAt (v
, x
, y
);
437 if (isBrowserContentView (parent
))
445 static bool isBrowserContentView (NSView
* v
)
447 return [[v className
] isEqualToString
: @
"WebNetscapePluginDocumentView"]
448 || [[v className
] isEqualToString
: @
"WebPluginDocumentView"]
449 || ([[v className
] isEqualToString
: @
"ChildView"] && ([v frame
].origin
.x
!= 0 && [v frame
].origin
.y
!= 0));
452 void setWindow (NPWindow
* window
)
454 const ScopedAutoReleasePool pool
;
458 NSView
* parentView
= nil
;
459 NP_CGContext
* const cgContext
= (window
!= nullptr) ? (NP_CGContext
*) window
->window
: nullptr;
460 log ("NP_CGContext: " + String::toHexString ((pointer_sized_int
) cgContext
));
463 WindowRef windowRef
= cgContext
!= nullptr ? (WindowRef
) cgContext
->window
: 0;
467 NSWindow
* win
= [[[NSWindow alloc
] initWithWindowRef
: windowRef
] autorelease
];
469 NSWindow
* win
= cgContext
!= nullptr ? (NSWindow
*) cgContext
->window
: nil
;
474 log ("window: " + nsStringToJuce ([win description
]));
476 const Rectangle
<int> clip (window
->clipRect
.left
, window
->clipRect
.top
,
477 window
->clipRect
.right
- window
->clipRect
.left
,
478 window
->clipRect
.bottom
- window
->clipRect
.top
);
479 const Rectangle
<int> target ((int) window
->x
, (int) window
->y
, (int) window
->width
, (int) window
->height
);
480 const Rectangle
<int> intersection (clip
.getIntersection (target
));
482 // in firefox the clip rect is usually out of step with the target rect, but in safari it matches
483 log ("plugin window clip: " + clip
.toString());
484 log ("plugin window target: " + target
.toString());
485 log ("plugin window intersection: " + intersection
.toString());
487 if (! intersection
.isEmpty())
489 NSView
* content
= [win contentView
];
490 log ("content: " + nsStringToJuce ([content description
]));
492 float wx
= (float) intersection
.getCentreX();
493 float wy
= (float) intersection
.getCentreY();
495 NSRect v
= [content convertRect
: [content frame
] toView
: nil
];
496 NSRect w
= [win frame
];
498 log ("wx: " + Rectangle
<int> (v
.origin
.x
, v
.origin
.y
, v
.size
.width
, v
.size
.height
).toString()
499 + " " + Rectangle
<int> (w
.origin
.x
, w
.origin
.y
, w
.size
.width
, w
.size
.height
).toString());
501 // adjust the requested window pos to deal with the content view's origin within the window
502 wy
-= w
.size
.height
- (v
.origin
.y
+ v
.size
.height
);
504 parentView
= findViewAt (content
, wx
, wy
);
506 if (! isBrowserContentView (parentView
))
507 parentView
= currentParentView
;
509 else if (currentParentView
!= nil
&& ! target
.isEmpty())
511 // Firefox can send lots of spurious resize messages when updating its pages, so this is a
512 // bodge to avoid flickering caused by repeatedly removing and re-adding the view..
513 parentView
= currentParentView
;
516 log ("parent: " + nsStringToJuce ([parentView description
]));
519 if (parentView
!= currentParentView
)
521 log ("new view: " + nsStringToJuce ([parentView description
]));
526 currentParentView
= parentView
;
528 if (parentView
!= nil
)
530 setSize (window
->width
, window
->height
);
531 addToDesktop (0, parentView
);
536 if (window
!= nullptr)
537 setSize (window
->width
, window
->height
);
542 //==============================================================================
543 static NPIdentifier
getIdentifierFromString (const var::identifier
& s
) noexcept
545 return browser
.getstringidentifier (s
.toString().toUTF8());
548 static const var
createValueFromNPVariant (NPP npp
, const NPVariant
& v
);
549 static void createNPVariantFromValue (NPP npp
, NPVariant
& out
, const var
& v
);
552 static int numDOWNP
= 0, numJuceSO
= 0;
555 //==============================================================================
556 class DynamicObjectWrappingNPObject
: public DynamicObject
559 NPObject
* const source
;
562 DynamicObjectWrappingNPObject (NPP npp_
, NPObject
* const source_
)
564 source (browser
.retainobject (source_
))
566 DBG ("num NP wrapper objs: " + String (++numDOWNP
));
569 ~DynamicObjectWrappingNPObject()
571 browser
.releaseobject (source
);
572 DBG ("num NP wrapper objs: " + String (--numDOWNP
));
575 var
getProperty (const var::identifier
& propertyName
) const
578 VOID_TO_NPVARIANT (result
);
579 browser
.getproperty (npp
, source
, getIdentifierFromString (propertyName
), &result
);
580 const var
v (createValueFromNPVariant (npp
, result
));
581 browser
.releasevariantvalue (&result
);
585 bool hasProperty (const var::identifier
& propertyName
) const
588 VOID_TO_NPVARIANT (result
);
589 const bool hasProp
= browser
.getproperty (npp
, source
, getIdentifierFromString (propertyName
), &result
);
590 browser
.releasevariantvalue (&result
);
594 void setProperty (const var::identifier
& propertyName
, const var
& newValue
)
597 createNPVariantFromValue (npp
, value
, newValue
);
599 browser
.setproperty (npp
, source
, getIdentifierFromString (propertyName
), &value
);
600 browser
.releasevariantvalue (&value
);
603 void removeProperty (const var::identifier
& propertyName
)
605 browser
.removeproperty (npp
, source
, getIdentifierFromString (propertyName
));
608 bool hasMethod (const var::identifier
& methodName
) const
610 return browser
.hasmethod (npp
, source
, getIdentifierFromString (methodName
));
613 var
invokeMethod (const var::identifier
& methodName
,
614 const var
* parameters
,
620 VOID_TO_NPVARIANT (result
);
622 if (numParameters
> 0)
624 HeapBlock
<NPVariant
> params (numParameters
);
627 for (i
= 0; i
< numParameters
; ++i
)
628 createNPVariantFromValue (npp
, params
[i
], parameters
[i
]);
630 if (browser
.invoke (npp
, source
, getIdentifierFromString (methodName
),
631 params
, numParameters
, &result
))
633 returnVal
= createValueFromNPVariant (npp
, result
);
634 browser
.releasevariantvalue (&result
);
637 for (i
= 0; i
< numParameters
; ++i
)
638 browser
.releasevariantvalue (¶ms
[i
]);
642 if (browser
.invoke (npp
, source
, getIdentifierFromString (methodName
), 0, 0, &result
))
644 returnVal
= createValueFromNPVariant (npp
, result
);
645 browser
.releasevariantvalue (&result
);
653 //==============================================================================
654 class NPObjectWrappingDynamicObject
: public NPObject
657 static NPObject
* create (NPP npp
, const var
& objectToWrap
);
659 virtual ~NPObjectWrappingDynamicObject()
661 DBG ("num Juce wrapper objs: " + String (--numJuceSO
));
665 NPObjectWrappingDynamicObject (NPP npp_
)
668 DBG ("num Juce wrapper objs: " + String (++numJuceSO
));
671 //==============================================================================
672 bool construct (const NPVariant
*args
, uint32_t argCount
, NPVariant
*result
);
675 bool hasMethod (NPIdentifier name
)
677 DynamicObject
* const o
= object
.getDynamicObject();
678 return o
!= nullptr && o
->hasMethod (identifierToString (name
));
681 bool invoke (NPIdentifier name
, const NPVariant
* args
, uint32_t argCount
, NPVariant
* out
)
683 DynamicObject
* const o
= object
.getDynamicObject();
684 const var::identifier
methodName (identifierToString (name
));
686 if (o
== nullptr || ! o
->hasMethod (methodName
))
691 ParamHolder (uint32_t num
) { params
= new var
[num
]; }
692 ~ParamHolder() { delete[] params
; }
697 ParamHolder
params (argCount
);
699 for (uint32_t i
= 0; i
< argCount
; ++i
)
700 params
.params
[i
] = createValueFromNPVariant (npp
, args
[i
]);
702 const var
result (o
->invokeMethod (methodName
, params
.params
, argCount
));
705 createNPVariantFromValue (npp
, *out
, result
);
710 bool invokeDefault (const NPVariant
* args
, uint32_t argCount
, NPVariant
* result
)
715 bool hasProperty (NPIdentifier name
)
717 DynamicObject
* const o
= object
.getDynamicObject();
718 return o
!= nullptr && o
->hasProperty (identifierToString (name
));
721 bool getProperty (NPIdentifier name
, NPVariant
* out
)
723 DynamicObject
* const o
= object
.getDynamicObject();
724 const var::identifier
propName (identifierToString (name
));
726 if (o
== nullptr || ! o
->hasProperty (propName
))
729 const var
result (o
->getProperty (propName
));
732 createNPVariantFromValue (npp
, *out
, result
);
737 bool setProperty (NPIdentifier name
, const NPVariant
* value
)
739 DynamicObject
* const o
= object
.getDynamicObject();
741 if (value
== nullptr || o
== nullptr)
744 o
->setProperty (identifierToString (name
), createValueFromNPVariant (npp
, *value
));
748 bool removeProperty (NPIdentifier name
)
750 DynamicObject
* const o
= object
.getDynamicObject();
751 const var::identifier
propName (identifierToString (name
));
753 if (o
== nullptr || ! o
->hasProperty (propName
))
756 o
->removeProperty (propName
);
760 bool enumerate (NPIdentifier
** identifier
, uint32_t* count
)
765 //==============================================================================
769 static const var::identifier
identifierToString (NPIdentifier id
)
771 NPUTF8
* const name
= browser
.utf8fromidentifier (id
);
772 const var::identifier
result ((const char*) name
);
773 browser
.memfree (name
);
778 //==============================================================================
779 static NPObject
* createInstance (NPP npp
, NPClass
* aClass
) { return new NPObjectWrappingDynamicObject (npp
); }
780 static void class_deallocate (NPObject
* npobj
) { delete (NPObjectWrappingDynamicObject
*) npobj
; }
781 static void class_invalidate (NPObject
* npobj
) { ((NPObjectWrappingDynamicObject
*) npobj
)->invalidate(); }
782 static bool class_hasMethod (NPObject
* npobj
, NPIdentifier name
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->hasMethod (name
); }
783 static bool class_invoke (NPObject
* npobj
, NPIdentifier name
, const NPVariant
* args
, uint32_t argCount
, NPVariant
* result
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->invoke (name
, args
, argCount
, result
); }
784 static bool class_invokeDefault (NPObject
* npobj
, const NPVariant
* args
, uint32_t argCount
, NPVariant
* result
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->invokeDefault (args
, argCount
, result
); }
785 static bool class_hasProperty (NPObject
* npobj
, NPIdentifier name
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->hasProperty (name
); }
786 static bool class_getProperty (NPObject
* npobj
, NPIdentifier name
, NPVariant
* result
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->getProperty (name
, result
); }
787 static bool class_setProperty (NPObject
* npobj
, NPIdentifier name
, const NPVariant
* value
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->setProperty (name
, value
); }
788 static bool class_removeProperty (NPObject
* npobj
, NPIdentifier name
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->removeProperty (name
); }
789 static bool class_enumerate (NPObject
* npobj
, NPIdentifier
** identifier
, uint32_t* count
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->enumerate (identifier
, count
); }
790 static bool class_construct (NPObject
* npobj
, const NPVariant
* args
, uint32_t argCount
, NPVariant
* result
) { return ((NPObjectWrappingDynamicObject
*) npobj
)->construct (args
, argCount
, result
); }
793 static NPClass sNPObjectWrappingDynamicObject_NPClass
=
795 #ifndef NP_CLASS_STRUCT_VERSION_ENUM
796 NP_CLASS_STRUCT_VERSION
, NPObjectWrappingDynamicObject::createInstance
,
797 NPObjectWrappingDynamicObject::class_deallocate
, NPObjectWrappingDynamicObject::class_invalidate
,
798 NPObjectWrappingDynamicObject::class_hasMethod
, NPObjectWrappingDynamicObject::class_invoke
,
799 NPObjectWrappingDynamicObject::class_invokeDefault
, NPObjectWrappingDynamicObject::class_hasProperty
,
800 NPObjectWrappingDynamicObject::class_getProperty
, NPObjectWrappingDynamicObject::class_setProperty
,
801 NPObjectWrappingDynamicObject::class_removeProperty
803 NP_CLASS_STRUCT_VERSION_ENUM
, NPObjectWrappingDynamicObject::createInstance
,
804 NPObjectWrappingDynamicObject::class_deallocate
, NPObjectWrappingDynamicObject::class_invalidate
,
805 NPObjectWrappingDynamicObject::class_hasMethod
, NPObjectWrappingDynamicObject::class_invoke
,
806 NPObjectWrappingDynamicObject::class_invokeDefault
, NPObjectWrappingDynamicObject::class_hasProperty
,
807 NPObjectWrappingDynamicObject::class_getProperty
, NPObjectWrappingDynamicObject::class_setProperty
,
808 NPObjectWrappingDynamicObject::class_removeProperty
, NPObjectWrappingDynamicObject::class_enumerate
812 bool NPObjectWrappingDynamicObject::construct (const NPVariant
* args
, uint32_t argCount
, NPVariant
* result
)
814 NPObject
* const newObj
= browser
.createobject (npp
, &sNPObjectWrappingDynamicObject_NPClass
);
816 if (newObj
== nullptr)
819 OBJECT_TO_NPVARIANT (newObj
, *result
);
823 NPObject
* NPObjectWrappingDynamicObject::create (NPP npp
, const var
& objectToWrap
)
825 jassert (objectToWrap
.getDynamicObject() != nullptr);
827 NPObject
* const nppObject
= browser
.createobject (npp
, &sNPObjectWrappingDynamicObject_NPClass
);
829 if (nppObject
!= nullptr)
830 ((NPObjectWrappingDynamicObject
*) nppObject
)->object
= objectToWrap
;
836 //==============================================================================
837 static const var
createValueFromNPVariant (NPP npp
, const NPVariant
& v
)
839 if (NPVARIANT_IS_BOOLEAN (v
))
840 return var (NPVARIANT_TO_BOOLEAN (v
));
841 else if (NPVARIANT_IS_INT32 (v
))
842 return var (NPVARIANT_TO_INT32 (v
));
843 else if (NPVARIANT_IS_DOUBLE (v
))
844 return var (NPVARIANT_TO_DOUBLE (v
));
845 else if (NPVARIANT_IS_STRING (v
))
847 return var (String::fromUTF8 ((const char*)
849 (NPVARIANT_TO_STRING (v
).UTF8Characters
), (int) NPVARIANT_TO_STRING (v
).UTF8Length
));
851 (NPVARIANT_TO_STRING (v
).utf8characters
), (int) NPVARIANT_TO_STRING (v
).utf8length
));
854 else if (NPVARIANT_IS_OBJECT (v
) && npp
!= nullptr)
855 return var (new DynamicObjectWrappingNPObject (npp
, NPVARIANT_TO_OBJECT (v
)));
860 static void createNPVariantFromValue (NPP npp
, NPVariant
& out
, const var
& v
)
863 INT32_TO_NPVARIANT ((int) v
, out
);
865 BOOLEAN_TO_NPVARIANT ((bool) v
, out
);
866 else if (v
.isDouble())
867 DOUBLE_TO_NPVARIANT ((double) v
, out
);
868 else if (v
.isString())
870 const String
s (v
.toString());
871 const char* const utf8
= s
.toUTF8();
872 const int utf8Len
= strlen (utf8
) + 1;
873 char* const stringCopy
= (char*) browser
.memalloc (utf8Len
);
874 memcpy (stringCopy
, utf8
, utf8Len
);
875 STRINGZ_TO_NPVARIANT (stringCopy
, out
);
877 else if (v
.getDynamicObject() != nullptr && npp
!= nullptr)
878 OBJECT_TO_NPVARIANT (NPObjectWrappingDynamicObject::create (npp
, v
), out
);
880 VOID_TO_NPVARIANT (out
);
883 //==============================================================================
884 class JucePluginInstance
887 //==============================================================================
888 JucePluginInstance (NPP npp_
)
890 holderComp (nullptr),
891 scriptObject (nullptr)
895 ~JucePluginInstance()
900 bool setWindow (NPWindow
* window
)
902 if (window
!= nullptr)
904 if (holderComp
== nullptr)
905 holderComp
= new BrowserPluginHolderComponent (npp
);
907 holderComp
->setWindow (window
);
911 deleteAndZero (holderComp
);
912 scriptObject
= nullptr;
918 NPObject
* getScriptableObject()
920 if (scriptObject
== nullptr)
921 scriptObject
= NPObjectWrappingDynamicObject::create (npp
, holderComp
->getObject());
923 if (scriptObject
!= nullptr && shouldRetainBrowserObject())
924 browser
.retainobject (scriptObject
);
929 //==============================================================================
931 BrowserPluginHolderComponent
* holderComp
;
932 NPObject
* scriptObject
;
935 bool shouldRetainBrowserObject() const
937 const String
version (browser
.uagent (npp
));
939 if (! version
.containsIgnoreCase (" AppleWebKit/"))
942 int versionNum
= version
.fromFirstOccurrenceOf (" AppleWebKit/", false, true).getIntValue();
944 return versionNum
== 0 || versionNum
>= 420;
948 //==============================================================================
949 static NPP currentlyInitialisingNPP
= nullptr;
950 static int numPluginInstances
= 0;
952 NPError
NPP_New (NPMIMEType pluginType
, NPP npp
, ::uint16 mode
, ::int16 argc
, char* argn
[], char* argv
[], NPSavedData
* saved
)
956 return NPERR_INVALID_INSTANCE_ERROR
;
959 browser
.setvalue (npp
, (NPPVariable
) NPNVpluginDrawingModel
, (void*) NPDrawingModelCoreGraphics
);
962 browser
.setvalue (npp
, (NPPVariable
) 1001 /*NPPVpluginEventModel*/, (void*) 1 /*NPEventModelCocoa*/);
964 browser
.setvalue (npp
, (NPPVariable
) 1001 /*NPPVpluginEventModel*/, 0 /*NPEventModelCarbon*/);
968 if (numPluginInstances
++ == 0)
970 log ("initialiseJuce_GUI()");
971 initialiseJuce_GUI();
974 currentlyInitialisingNPP
= npp
;
975 JucePluginInstance
* p
= new JucePluginInstance (npp
);
976 currentlyInitialisingNPP
= nullptr;
978 npp
->pdata
= (void*) p
;
979 return NPERR_NO_ERROR
;
982 NPError
NPP_Destroy (NPP npp
, NPSavedData
** save
)
986 return NPERR_INVALID_INSTANCE_ERROR
;
988 JucePluginInstance
* const p
= (JucePluginInstance
*) npp
->pdata
;
994 if (--numPluginInstances
== 0)
996 log ("shutdownJuce_GUI()");
998 browserVersionDesc
= String::empty
;
1002 return NPERR_NO_ERROR
;
1005 NPError
NPP_SetWindow (NPP npp
, NPWindow
* pNPWindow
)
1008 return NPERR_INVALID_INSTANCE_ERROR
;
1010 if (pNPWindow
== nullptr)
1011 return NPERR_GENERIC_ERROR
;
1013 JucePluginInstance
* const p
= (JucePluginInstance
*) npp
->pdata
;
1016 return NPERR_GENERIC_ERROR
;
1018 currentlyInitialisingNPP
= npp
;
1019 NPError result
= p
->setWindow (pNPWindow
) ? NPERR_NO_ERROR
1020 : NPERR_MODULE_LOAD_FAILED_ERROR
;
1021 currentlyInitialisingNPP
= nullptr;
1025 //==============================================================================
1026 NPError
NPP_GetValue (NPP npp
, NPPVariable variable
, void* value
)
1029 return NPERR_INVALID_INSTANCE_ERROR
;
1031 JucePluginInstance
* const p
= (JucePluginInstance
*) npp
->pdata
;
1034 return NPERR_GENERIC_ERROR
;
1038 case NPPVpluginNameString
: *((const char**) value
) = JuceBrowserPlugin_Name
; break;
1039 case NPPVpluginDescriptionString
: *((const char**) value
) = JuceBrowserPlugin_Desc
; break;
1040 case NPPVpluginScriptableNPObject
: *((NPObject
**) value
) = p
->getScriptableObject(); break;
1041 default: return NPERR_GENERIC_ERROR
;
1044 return NPERR_NO_ERROR
;
1047 NPError
NPP_NewStream (NPP npp
, NPMIMEType type
, NPStream
* stream
, NPBool seekable
, ::uint16
* stype
)
1050 return NPERR_INVALID_INSTANCE_ERROR
;
1052 return NPERR_NO_ERROR
;
1055 ::int32
NPP_WriteReady (NPP npp
, NPStream
*stream
)
1058 return NPERR_INVALID_INSTANCE_ERROR
;
1063 ::int32
NPP_Write (NPP npp
, NPStream
*stream
, ::int32 offset
, ::int32 len
, void *buffer
)
1066 return NPERR_INVALID_INSTANCE_ERROR
;
1071 NPError
NPP_DestroyStream (NPP npp
, NPStream
*stream
, NPError reason
)
1074 return NPERR_INVALID_INSTANCE_ERROR
;
1076 return NPERR_NO_ERROR
;
1079 void NPP_StreamAsFile (NPP npp
, NPStream
* stream
, const char* fname
)
1085 void NPP_Print (NPP npp
, NPPrint
* printInfo
)
1091 void NPP_URLNotify (NPP npp
, const char* url
, NPReason reason
, void* notifyData
)
1097 NPError
NPP_SetValue (NPP npp
, NPNVariable variable
, void* value
)
1100 return NPERR_INVALID_INSTANCE_ERROR
;
1102 return NPERR_NO_ERROR
;
1105 ::int16
NPP_HandleEvent (NPP npp
, void* ev
)
1109 //JucePluginInstance* const p = (JucePluginInstance*) npp->pdata;
1116 //==============================================================================
1117 static NPP
getInstance (const BrowserPluginComponent
* bpc
)
1119 BrowserPluginHolderComponent
* holder
= dynamic_cast <BrowserPluginHolderComponent
*> (bpc
->getParentComponent());
1121 if (holder
!= nullptr)
1124 return currentlyInitialisingNPP
;
1127 //==============================================================================
1128 BrowserPluginComponent::BrowserPluginComponent()
1132 BrowserPluginComponent::~BrowserPluginComponent()
1136 const String
BrowserPluginComponent::getBrowserVersion() const
1138 if (browserVersionDesc
.isEmpty())
1140 if (getInstance (this) != nullptr)
1141 browserVersionDesc
<< browser
.uagent (getInstance (this));
1143 browserVersionDesc
<< "Netscape Plugin V" << (int) ((browser
.version
>> 8) & 0xff)
1144 << "." << (int) (browser
.version
& 0xff);
1147 return browserVersionDesc
;
1150 //==============================================================================
1152 extern const String
getActiveXBrowserURL (const BrowserPluginComponent
* comp
);
1155 const String
BrowserPluginComponent::getBrowserURL() const
1160 result
= getActiveXBrowserURL (this);
1162 if (result
.isNotEmpty())
1166 // (FireFox doesn't seem happy if you call this from a background thread..)
1167 jassert (MessageManager::getInstance()->isThisTheMessageThread());
1169 NPP npp
= getInstance (this);
1172 NPObject
* windowObj
= nullptr;
1173 browser
.getvalue (npp
, NPNVWindowNPObject
, &windowObj
);
1175 if (windowObj
!= nullptr)
1178 bool ok
= browser
.getproperty (npp
, windowObj
,
1179 browser
.getstringidentifier ("location"), &location
);
1180 browser
.releaseobject (windowObj
);
1186 ok
= browser
.getproperty (npp
, location
.value
.objectValue
,
1187 browser
.getstringidentifier ("href"), &href
);
1188 browser
.releasevariantvalue (&location
);
1193 result
= URL::removeEscapeChars (createValueFromNPVariant (npp
, href
).toString());
1194 browser
.releasevariantvalue (&href
);